package org.jeecg.demo.wx.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.common.exception.JeecgBootException;

import org.jeecg.demo.wx.convert.ScheduleTransfer;
import org.jeecg.demo.wx.dto.QueryIdDto;
import org.jeecg.demo.wx.dto.QueryTaskDto;
import org.jeecg.demo.wx.dto.QueryUserTaskInfoDto;
import org.jeecg.demo.wx.dto.RlSchedulePageDto;
import org.jeecg.demo.wx.entity.RlSchedule;
import org.jeecg.demo.wx.entity.RlTask;
import org.jeecg.demo.wx.enumeration.*;
import org.jeecg.demo.wx.mapper.RlScheduleMapper;
import org.jeecg.demo.wx.mapper.RlTaskMapper;
import org.jeecg.demo.wx.service.IRlScheduleService;
import org.jeecg.demo.wx.service.IRlTaskService;
import org.jeecg.demo.wx.util.PageData;
import org.jeecg.demo.wx.vo.QueryScheduleVO;
import org.jeecg.demo.wx.vo.TaskInfoVO;
import org.jeecg.demo.wx.vo.WorkHandlingVO;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


@Service
public class RlScheduleServiceImpl extends ServiceImpl<RlScheduleMapper, RlSchedule> implements IRlScheduleService {

    @Autowired
    @Lazy
    private IRlTaskService iRlTaskService;

    @Resource
    private RlTaskMapper rlTaskMapper;
    @Autowired
    private ISysUserService sysUserService;

    public List<QueryScheduleVO> splitDate(List<RlSchedule> userSchedule) {
        // 切割时间
        List<QueryScheduleVO> userScheduleVo = ScheduleTransfer.INSTANCE.toQuerySchedule(userSchedule);
        userScheduleVo.forEach(item -> {
            item.setBeginDate(DateUtil.format(item.getBeginTime(), "yyyy-MM-dd"));
            item.setBeginDateTime(DateUtil.format(item.getBeginTime(), "HH:mm"));
            item.setEndDate(DateUtil.format(item.getEndTime(), "yyyy-MM-dd"));
            item.setEndDateTime(DateUtil.format(item.getEndTime(), "HH:mm"));
        });
        return userScheduleVo;
    }
    /**
     * 默认查询七天内日程数据，条件查询未已完成、未完成和所有
     *
     * @param dto
     * @return
     */
    @Override
    public Map<String, List<QueryScheduleVO>> queryPageList(RlSchedulePageDto dto) {
        List<RlSchedule> userSchedule = new ArrayList<>();
        if (StrUtil.isNotBlank(dto.getStatus())) {
            LambdaQueryWrapper<RlSchedule> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(RlSchedule::getUserId, dto.getUserId())
                    .eq(RlSchedule::getDelFlag, DelEnum.True.getCode())
                    .ne(RlSchedule::getIsComplete, CompleteEnum.ARCHIVE.getCode())
                    .le(ObjectUtil.isNotEmpty(dto.getEndTime()), RlSchedule::getBeginTime, dto.getEndTime())
                    .ge(ObjectUtil.isNotEmpty(dto.getStartTime()), RlSchedule::getBeginTime, dto.getStartTime());
            // 所有
            if (dto.getStatus().equals(QueryEnum.ALL_SCHEDULE.getCode())) {
                userSchedule = this.list(wrapper);
            } else if (dto.getStatus().equals(QueryEnum.COMPLETED_SCHEDULE.getCode())){
                // 已完成
                wrapper.eq(RlSchedule::getIsComplete, CompleteEnum.FINISH.getCode());
                userSchedule = this.list(wrapper);
            } else if (dto.getStatus().equals(QueryEnum.NOT_COMPLETED_SCHEDULE.getCode())) {
                // 未完成（已读+超时）
                wrapper.in(RlSchedule::getIsComplete, Arrays.asList(CompleteEnum.READ.getCode(), CompleteEnum.OVERTIME.getCode()));
                userSchedule = this.list(wrapper);
            } else if (dto.getStatus().equals(QueryEnum.UNREAD_SCHEDULE.getCode())) {
                // 未读
                wrapper.eq(RlSchedule::getIsComplete, CompleteEnum.UNREAD.getCode());
                userSchedule = this.list(wrapper);
            } else if (dto.getStatus().equals(QueryEnum.WEEK_SCHEDULE.getCode())) {
                // 七天
                DateTime date = DateUtil.date();
                DateTime start = DateUtil.beginOfDay(date);
                DateTime end = DateUtil.offsetDay(start, 7);
                userSchedule = this.lambdaQuery()
                        .eq(RlSchedule::getUserId, dto.getUserId())
                        .eq(RlSchedule::getDelFlag, DelEnum.True.getCode())
                        .and(e -> e.between(RlSchedule::getBeginTime, start, end)
                                    .or()
                                    .between(RlSchedule::getEndTime, start, end)
                        )
                        .list();
            } else if (dto.getStatus().equals(QueryEnum.OVERTIME_SCHEDULE.getCode())) {
                // 超期
                wrapper.eq(RlSchedule::getIsComplete, CompleteEnum.OVERTIME.getCode());
                userSchedule = this.list(wrapper);
            }
        } else {
            throw new JeecgBootException("日程查询参数不能为空！");
        }
        // 更新超时日程
        this.queryOvertimeSchedule();
        // 根据时间间隔区分，每个区间都要有数据，深克隆
        List<RlSchedule> splitTimeList = new ArrayList<>();
        userSchedule.forEach(e -> {
            List<DateTime> timeInterval = DateUtil.
                    rangeToList(e.getBeginTime(), e.getEndTime(), DateField.DAY_OF_YEAR);
            if (timeInterval.size() > 0) {
                for (int i = 1; i < timeInterval.size(); i++) {
                    RlSchedule obj = ObjectUtil.cloneByStream(e);
                    RlSchedule tempSchedule = obj.setBeginTime(timeInterval.get(i));
                    splitTimeList.add(tempSchedule);
                }
            }
        });
        userSchedule.addAll(splitTimeList);

        // 切割时间
        List<QueryScheduleVO> userScheduleVo = this.splitDate(userSchedule);

        // 文件路径转换
        userScheduleVo.forEach(e -> e.setFilePath(iRlTaskService.convertFilePath(e.getFilePath())));
        // 根据日期进行排序
        Map<String, List<QueryScheduleVO>> dayMap =  userScheduleVo.stream()
                .collect(Collectors.groupingBy(QueryScheduleVO::getBeginDate));

        Map<String, List<QueryScheduleVO>> results = new LinkedHashMap<>();
        // 根据key排序
        dayMap.entrySet().stream()
                // 设置字典，值转文
                .peek(e -> {
                    for (QueryScheduleVO vo : e.getValue()) {
                        vo.setIsRepeatText(vo.getIsRepeat().equals(EnabledEnum.True.getCode())
                              ? EnabledEnum.True.getMsg() : EnabledEnum.False.getMsg());
                        vo.setIsHolidayText(vo.getIsHoliday().equals(EnabledEnum.True.getCode())
                              ? EnabledEnum.True.getMsg() : EnabledEnum.False.getMsg());
                        vo.setIsWeekendText(vo.getIsWeekend().equals(EnabledEnum.True.getCode())
                              ? EnabledEnum.True.getMsg() : EnabledEnum.False.getMsg());
                        vo.setTaskEnabledText(vo.getDelFlag().equals(DelEnum.True.getCode())
                              ? EnabledEnum.True.getMsg() : EnabledEnum.False.getMsg());
                        vo.setStateText(vo.getState().equals(StateEnum.SCHEDULE.getCode())
                              ? StateEnum.SCHEDULE.getMsg() : StateEnum.TASK.getMsg());
                        vo.setLevelText(vo.getLevel().equals(LevalEnum.COMMON.getCode())
                              ? LevalEnum.COMMON.getMsg() : LevalEnum.IMPORTANT.getMsg());
                        for (CompleteEnum value : CompleteEnum.values()) {
                            if (vo.getIsComplete().equals(value.getCode())) {
                                vo.setIsCompleteText(value.getMsg());
                                break;
                            }
                        }
                        String address = null;
                        if (vo.getAddress() != null) {
                            for (String item : vo.getAddress().split(",")) {
                                for (AddressEnum value : AddressEnum.values()) {
                                    if (item.equals(value.getCode()) && address==null) {
                                        address = value.getMsg();
                                        break;
                                    } else if (item.equals(value.getCode())) {
                                        address = String.join(",", address, value.getMsg());
                                        break;
                                    }
                                }
                            }
                            vo.setAddress(address);
                        }
                        // 任务则set信息
                        if (ObjectUtil.isNotEmpty(vo.getTaskId())) {
                            RlTask task = iRlTaskService.lambdaQuery().eq(RlTask::getId, vo.getTaskId()).one();
                            vo.setCreator(task.getUserName())
                              .setDepName(task.getDepName());
                        }
                    }
                })
                .sorted(Map.Entry.comparingByKey(Comparator.reverseOrder()))
                // forEO是按照顺序进行的
                 .forEachOrdered(e -> results.put(e.getKey(), e.getValue()));
        return results;
    }

    /**
     * 更新超时日程
     */
    private void queryOvertimeSchedule() {
        List<RlSchedule> list = this.lambdaQuery()
                .ne(RlSchedule::getIsComplete, CompleteEnum.OVERTIME.getCode())
                .ne(RlSchedule::getIsComplete, CompleteEnum.FINISH.getCode())
                .ne(RlSchedule::getIsComplete, CompleteEnum.ARCHIVE.getCode())
                .list();
        List<RlSchedule> update = list.stream()
                .filter(e -> e.getEndTime().before(DateUtil.date()))
                .peek(e -> {
                    // OA任务超时自动完成
                    if ((e.getIsOa() != null) && (e.getIsOa().equals(EnabledEnum.True.getCode()))) {
                        e.setIsComplete(CompleteEnum.FINISH.getCode());
                    } else {
                        e.setIsComplete(CompleteEnum.OVERTIME.getCode());
                    }
                })
                .collect(Collectors.toList());
        this.updateBatchById(update);
    }

    /**
     * 查询当天计划
     * @param dto
     * @return
     */
    @Override
    public List<QueryScheduleVO> queryPlanDay(QueryIdDto dto) {
        List<RlSchedule> userSchedule = this.lambdaQuery()
                .eq(RlSchedule::getUserId, dto.getUserId())
                .le(RlSchedule::getBeginTime, DateUtil.beginOfDay(DateUtil.date()))
                .ge(RlSchedule::getEndTime, DateUtil.endOfDay(DateUtil.date()))
                .list();

        // 切割时间
        List<QueryScheduleVO> userScheduleVo = this.splitDate(userSchedule);
        userScheduleVo.forEach(e -> e.setFilePath(iRlTaskService.convertFilePath(e.getFilePath())));
        return userScheduleVo;
    }

    /**
     * 添加日程默认已读
     * @param rlSchedule
     */
    @Override
    public void saveSchedule(RlSchedule rlSchedule) {
        rlSchedule.setIsComplete(CompleteEnum.READ.getCode())
                .setState(StateEnum.SCHEDULE.getCode())
                .setDelFlag(DelEnum.True.getCode())
                .setIsRepeat("").setIsHoliday("").setIsWeekend("");
        this.save(rlSchedule);
    }

    @Override
    public Page<RlSchedule> queryUserTaskInfo(QueryUserTaskInfoDto dto) {
        if (dto.getState().equals(QueryEnum.MEETING_SCHEDULE.getCode())) {
            return this.lambdaQuery()
                    .eq(RlSchedule::getIsOa, EnabledEnum.True.getCode())
                    .eq(RlSchedule::getUserId, dto.getUserId())
                    .eq(RlSchedule::getDelFlag, DelEnum.True.getCode())
                    .orderByDesc(RlSchedule::getCreateTime)
                    .page(new Page<>(dto.getPageNo(), dto.getPageSize()));
        } else if (dto.getState().equals(CompleteEnum.FINISH.getCode())) {
            return this.lambdaQuery()
                    .eq(RlSchedule::getUserId, dto.getUserId())
                    .and(e -> e.eq(RlSchedule::getIsComplete, CompleteEnum.ARCHIVE.getCode())
                            .or()
                            .eq(RlSchedule::getIsComplete, CompleteEnum.FINISH.getCode()))
                    .eq(RlSchedule::getDelFlag, DelEnum.True.getCode())
                    .orderByDesc(RlSchedule::getCreateTime)
                    .page(new Page<>(dto.getPageNo(), dto.getPageSize()));
        } else {
            return this.lambdaQuery()
                    .eq(RlSchedule::getUserId, dto.getUserId())
                    .eq(RlSchedule::getIsComplete, dto.getState())
                    .eq(RlSchedule::getDelFlag, DelEnum.True.getCode())
                    .orderByDesc(RlSchedule::getCreateTime)
                    .page(new Page<>(dto.getPageNo(), dto.getPageSize()));
        }
    }

    @Override
    public void modifyScheduleState(Integer id, String isComplete) {
        this.lambdaUpdate()
                .eq(RlSchedule::getId, id)
                .set(RlSchedule::getIsComplete, isComplete)
                .update();
    }

    /** 工作处理接口
     * @param dto
     * @return
     */
    @Override
    public PageData<WorkHandlingVO> workHandling(QueryTaskDto dto) {
        // 时间过滤
        LambdaQueryWrapper<RlSchedule> wrapper = new LambdaQueryWrapper<>();
        if (ObjectUtil.isNotEmpty(dto.getStartTime())) {
            wrapper.ge(RlSchedule::getBeginTime, DateUtil.beginOfDay(dto.getStartTime()));
        }
        if (ObjectUtil.isNotEmpty(dto.getEndTime())) {
            wrapper.le(RlSchedule::getEndTime, DateUtil.endOfDay(dto.getEndTime()));
        }
        if (StrUtil.isBlank(dto.getType())) {
            throw new JeecgBootException("type参数不能为空！");
        }
        // 排除归档，选择类型
        wrapper.eq(RlSchedule::getUserId, dto.getUserId())
                .eq(RlSchedule::getDelFlag, DelEnum.True.getCode())
                .eq(RlSchedule::getState, dto.getType())
                .ne(RlSchedule::getIsComplete, CompleteEnum.ARCHIVE.getCode())
                .orderByDesc(RlSchedule::getCreateTime);
        Page<RlSchedule> page = this.page(dto.getPage(), wrapper);

        List<RlSchedule> taskList = this.queryScheduleFilter(page.getRecords(), dto.getStatus());
        // 文件路径转换及排序
        List<RlSchedule> collect = taskList.stream()
                .map(e -> e.setFilePath(iRlTaskService.convertFilePath(e.getFilePath())))
                .sorted(Comparator.comparing(RlSchedule::getBeginTime).reversed())
                .collect(Collectors.toList());

        List<WorkHandlingVO> workHandling = ScheduleTransfer.INSTANCE.toWorkHandling(collect);
        // 添加task表信息
        if (dto.getType().equals(StateEnum.TASK.getCode())) {
            for (WorkHandlingVO item : workHandling) {
                TaskInfoVO byId = rlTaskMapper.findById(item.getTaskId());
                item.setTaskInfo(byId);
            }
        }
        return PageData.convertPageData(page, workHandling);
    }

    /**
     * @param records
     * @param status
     * @return
     */
    @Override
    public List<RlSchedule> queryScheduleFilter(List<RlSchedule> records, String status) {
        List<RlSchedule> result = new ArrayList<>();
        // 已完成
        if (status.equals(QueryEnum.COMPLETED_SCHEDULE.getCode())) {
            result = records.stream().filter(e ->
                    e.getIsComplete().equals(CompleteEnum.FINISH.getCode())).collect(Collectors.toList());
        // 超期未完成
        } else if (status.equals(QueryEnum.OVERTIME_SCHEDULE.getCode())) {
            result = records.stream().filter(e ->
                    e.getIsComplete().equals(CompleteEnum.OVERTIME.getCode())).collect(Collectors.toList());
            // 未完成
        } else if (status.equals(QueryEnum.NOT_COMPLETED_SCHEDULE.getCode())) {
            result = records.stream().filter(e ->
                    Arrays.asList(CompleteEnum.READ.getCode(), CompleteEnum.OVERTIME.getCode()).contains(e.getIsComplete()))
                    .collect(Collectors.toList());
            // 未读
        } else if (status.equals(QueryEnum.UNREAD_SCHEDULE.getCode())) {
            result = records.stream().filter(e ->
                    e.getIsComplete().equals(CompleteEnum.UNREAD.getCode())).collect(Collectors.toList());
        } else {
            return records;
        }
        return result;
    }

    /** 归档任务
     * @param id
     */
    @Override
    public void archiveTask(String id) {
        this.lambdaUpdate()
                .eq(RlSchedule::getId, id)
                .set(RlSchedule::getIsComplete, CompleteEnum.ARCHIVE.getCode())
                .update();
    }

    /**
     * @param id
     */
    @Override
    public void removeScheduleById(String id) {
        this.lambdaUpdate()
                .set(RlSchedule::getDelFlag, DelEnum.False.getCode())
                .eq(RlSchedule::getId, id)
                .update();

    }

}
